#include "book.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include "tcpclient.h"
#include <QInputDialog>
#include <QMessageBox>
#include <QFileInfo>
#include <QFileDialog>
#include "operatewidget.h"
#include "friend.h"
#include "sharefile.h"

Book::Book(QWidget *parent)
    : QWidget{parent}
{
    m_timer = new QTimer;
    m_download_flag = false;

    m_book_list_widget = new QListWidget;
    m_returnPB = new QPushButton("返回");
    m_create_dirPB = new QPushButton("创建文件夹");
    m_del_dirPB = new QPushButton("删除文件");
    m_renamePB = new QPushButton("重名名文件");
    m_flush_filePB = new QPushButton("刷新文件");

    QVBoxLayout* dir_vbl = new QVBoxLayout;
    dir_vbl->addWidget(m_returnPB);
    dir_vbl->addWidget(m_create_dirPB);
    dir_vbl->addWidget(m_del_dirPB);
    dir_vbl->addWidget(m_renamePB);
    dir_vbl->addWidget(m_flush_filePB);

    m_uploadPB = new QPushButton("上传文件");
    m_downloadPB = new QPushButton("下载文件");
    // m_del_filePB = new QPushButton("无用, 可删");
    m_share_filePB = new QPushButton("共享文件");
    m_move_filePB = new QPushButton("移动文件");
    m_select_dirPB = new QPushButton("选择目标文件");
    m_select_dirPB->setEnabled(false);

    QVBoxLayout* file_vbl = new QVBoxLayout;
    file_vbl->addWidget(m_uploadPB);
    file_vbl->addWidget(m_downloadPB);
    // file_vbl->addWidget(m_del_filePB);
    file_vbl->addWidget(m_share_filePB);
    file_vbl->addWidget(m_move_filePB);
    file_vbl->addWidget(m_select_dirPB);

    QHBoxLayout* all_hbl = new QHBoxLayout;
    all_hbl->addWidget(m_book_list_widget);
    all_hbl->addLayout(dir_vbl);
    all_hbl->addLayout(file_vbl);

    setLayout(all_hbl);

    this->flush_file(); //一开始就刷新文件

    // str_enter_folder = TcpClient::getInstance().get_current_dir(); //初始化当前目录

    m_enter_dir = "";
    m_go_back_dir.clear();

    connect(m_create_dirPB, &QPushButton::clicked, this, [&]() {
        QString new_dir = QInputDialog::getText(this, "新建文件夹",
                                                "请输入新文件夹名称");
        if (!new_dir.isEmpty()) {
            if (new_dir.size() > 32) {
                QMessageBox::warning(this, "新建文件夹", "文件夹名称长度不能超过32");
                //return;
            } else {
                QString name = TcpClient::getInstance().get_login_name();
                QString cur_path = TcpClient::getInstance().get_current_dir();
                PDU* pdu = makePDU(cur_path.size()+1);
                pdu->uiMsgType = ENUM_MSG_TYPE_CREATE_DIR_REQUEST;
                strncpy(pdu->caData, name.toStdString().c_str(), 32);
                strncpy(pdu->caData+32, new_dir.toStdString().c_str(), 32);
                strncpy((char*)pdu->caMsg, cur_path.toStdString().c_str(), cur_path.size());

                TcpClient::getInstance().getTcpSocket().write((char*)pdu, pdu->uiPDULen);
                // pdu->printPDU();
                free(pdu); pdu = NULL;
            }
        } else
            QMessageBox::warning(this, "新建文件夹", "请输入文件夹名称");
    });

    //刷新文件的函数不写成匿名函数, 因为其他操作也需要刷新文件, 方便调用
    connect(m_flush_filePB, &QPushButton::clicked, this, &Book::flush_file);

    connect(m_del_dirPB, &QPushButton::clicked, this, [&]() {
        QListWidgetItem* item = m_book_list_widget->currentItem();
        if (!item) {
            QMessageBox::information(this, "没有选择文件", "请选择要删除的文件");
            return;
        }
        QString del_name = item->text();

        QString cur_path = TcpClient::getInstance().get_current_dir();
        PDU* pdu = makePDU(cur_path.size()+1);
        pdu->uiMsgType = ENUM_MSG_TYPE_DEL_FILE_REQUEST;
        strncpy((char*)pdu->caMsg, cur_path.toStdString().c_str(), cur_path.size());
        strncpy(pdu->caData, del_name.toStdString().c_str(), del_name.size());
        TcpClient::getInstance().getTcpSocket().write((char*)pdu, pdu->uiPDULen);
        // pdu->printPDU();
        free(pdu); pdu = NULL;
    });

    connect(m_renamePB, &QPushButton::clicked, this, [&]() {
        QListWidgetItem* item = m_book_list_widget->currentItem();
        if (!item) {
            QMessageBox::information(this, "没有选择文件", "请选择要重命名的文件");
            return;
        }
        QString old_name = item->text();
        QString new_name = QInputDialog::getText(this, "文件新名字",
                                                "请输入新文件名称");

        // qDebug() << "old_path:" << old_name << endl
        //          << "new_path:" << new_name;
        if (!new_name.isEmpty()) {
            if (new_name.size() > 32) {
                QMessageBox::warning(this, "新文件名过长", "文件名称长度不能超过32");
                return;
            }
            QString cur_path = TcpClient::getInstance().get_current_dir();
            PDU* pdu = makePDU(cur_path.size()+1);
            pdu->uiMsgType = ENUM_MSG_TYPE_RENAME_FILE_REQUEST;
            strncpy((char*)pdu->caMsg, cur_path.toStdString().c_str(), cur_path.size());
            strncpy(pdu->caData, old_name.toStdString().c_str(), old_name.size());
            strncpy(pdu->caData+32, new_name.toStdString().c_str(), new_name.size());
            TcpClient::getInstance().getTcpSocket().write((char*)pdu, pdu->uiPDULen);
            // pdu->printPDU();
            free(pdu); pdu = NULL;
        }
    });

    connect(m_book_list_widget, &QListWidget::doubleClicked, this, [&](const QModelIndex &index) {
        QListWidgetItem* tmp;
        tmp = m_book_list_widget->item(index.row());
        if (!tmp) return;
        QString dir_name = tmp->text();
        m_enter_dir = dir_name;
        // qDebug() << dir_path;
        PDU* pdu;
        if (dir_name == "." || dir_name == "..") {  //.表示当前目录, 这不用处理
            return;
        }/* else if (dir_name == "..") { //..表示上一级目录
            this->dir_go_back();
            return;
        }*/

        QString cur_path = TcpClient::getInstance().get_current_dir();
        pdu = makePDU(cur_path.size()+1);
        pdu->uiMsgType = ENUM_MSG_TYPE_ENTER_FOLDER_REQUEST;
        strncpy((char*)pdu->caMsg, cur_path.toStdString().c_str(), cur_path.size());
        strncpy(pdu->caData, dir_name.toStdString().c_str(), dir_name.size());

        TcpClient::getInstance().getTcpSocket().write((char*)pdu, pdu->uiPDULen);
        // pdu->printPDU();
        free(pdu); pdu = NULL;
    });

    connect(m_returnPB, &QPushButton::clicked, this, [&]() {
        QString cur_path = TcpClient::getInstance().get_current_dir();
        QString root_path = "./" + TcpClient::getInstance().get_login_name();
        if (cur_path == root_path) {
            QMessageBox::warning(this, "返回失败", "当前是用户根目录,不能在返回了");
            return;
        }
        int index = cur_path.lastIndexOf('/'); //找到斜杠的位置
        // qDebug() << "斜杠:" << index;
        cur_path.remove(index, cur_path.size()-index); //"./jack/abc" 9-6 = 3;
        // qDebug() << cur_path;
        TcpClient::getInstance().set_current_dir(cur_path); //更新当前目录
        this->clear_enter_dir();
        this->flush_file(); //刷新目录
    });

    connect(m_uploadPB, &QPushButton::clicked, this, [&]() {
        QString cur_path = TcpClient::getInstance().get_current_dir();
        m_upload_file_path = QFileDialog::getOpenFileName();
        // qDebug() << upload_file_path;
        if (m_upload_file_path.isEmpty()) {
            QMessageBox::warning(this, "没有选择文件", "请选择要上传的文件");
        } else {
            int index = m_upload_file_path.lastIndexOf('/');
            QString file_name = m_upload_file_path.right(m_upload_file_path.size() - index - 1);
            // qDebug() << file_name;

            QFile file(m_upload_file_path);
            int size_ = file.size();
            PDU* pdu = makePDU(cur_path.size()+1);
            pdu->uiMsgType = ENUM_MSG_TYPE_UPLOAD_FILE_REQUEST;
            strncpy((char*)pdu->caMsg, cur_path.toStdString().c_str(), cur_path.size());
            sprintf(pdu->caData, "%s %lld", file_name.toStdString().c_str(), size_);

            TcpClient::getInstance().getTcpSocket().write((char*)pdu, pdu->uiPDULen);
            // pdu->printPDU();
            free(pdu); pdu = NULL;

            //刚发完文件的信息, 不能接着就发送文件, 可能会出现粘包的现象, 需要添加一个定时器, 过了多少秒后才开始发送
            m_timer->start(1000); //1000毫秒
        }
    });

    //刚发完文件的信息, 不能接着就发送文件, 可能会出现粘包的现象, 需要添加一个定时器, 过了多少秒后才开始发送
    connect(m_timer, &QTimer::timeout, this, [&]() {
        m_timer->stop();
        // 有人曾经做过实验, 缓冲区大小为`4096`, 它的读写效率较高
        QFile file(m_upload_file_path);
        if (!file.open(QIODevice::ReadOnly) ) {
            QMessageBox::warning(this, "上传失败", "打开文件失败");
            return;
        }

        char* buf = new char[4096];
        qint64 ret = 0;
        while (1) {
            ret = file.read(buf, 4096);
            qDebug() << "ret = " << ret;
            if (ret > 0 && ret <= 4096) {
                TcpClient::getInstance().getTcpSocket().write(buf, ret);
            } else if (ret == 0) { //读到文件末尾
                break;
            } else {
                QMessageBox::warning(this, "上传失败", "上传失败");
                break;
            }
        }

        file.close();
        delete []buf;
        buf = NULL;
    });

    connect(m_downloadPB, &QPushButton::clicked, this, [&]() {
        //选择要下载的文件
        QListWidgetItem* item = m_book_list_widget->currentItem();
        if (!item) {
            QMessageBox::warning(this, "没有选择文件", "请选择要下载的文件");
            return;
        }
        //选择文件保存在哪
        m_save_path = QFileDialog::getSaveFileName();
        if (m_save_path.isEmpty()) {
            QMessageBox::warning(this, "没有选择文件", "请选择要保存在哪");
            m_save_path.clear();
        }
        QString cur_path = TcpClient::getInstance().get_current_dir();
        PDU* pdu = makePDU(cur_path.size()+1);
        pdu->uiMsgType = ENUM_MSG_TYPE_DOWNLOAD_FILE_REQUEST;
        strncpy((char*)pdu->caMsg, cur_path.toStdString().c_str(), cur_path.size());
        strncpy(pdu->caData, item->text().toStdString().c_str(), item->text().size());

        TcpClient::getInstance().getTcpSocket().write((char*)pdu, pdu->uiPDULen);
        // pdu->printPDU();
        free(pdu); pdu = NULL;

    });

    connect(m_share_filePB, &QPushButton::clicked, this, [&]() {
        Friend* p_friend = OperateWidget::getInstance().getFriend();
        // p_friend->flush_friend_func();  //先刷新好友
        QListWidget* friend_list = p_friend->friendListWidget();
        ShareFile::getInstance().update_friend(friend_list);
        // ShareFile s;
        // s.show();
        QListWidgetItem* item = m_book_list_widget->currentItem();
        if (!item) {
            QMessageBox::warning(this, "没有选择文件", "请选择要分享的文件");
            return;
        }
        if (item->text() == "." || item->text() == "..") {  //.表示当前目录, 这不用处理
            return;
        }
        m_shar_file_name = item->text();  //选中的是文件还是目录交给服务器判断

        if (ShareFile::getInstance().isHidden())
            ShareFile::getInstance().show();
    });

    connect(m_move_filePB, &QPushButton::clicked, this, [&]() {
        QListWidgetItem* item = m_book_list_widget->currentItem();
        if (!item) {
            QMessageBox::warning(this, "没有选择文件", "请选择要移动的文件");
            return;
        }
        m_move_file_name = item->text();
        QString cur_dir = TcpClient::getInstance().get_current_dir();
        m_move_file_path = cur_dir + "/" + m_move_file_name;
        qDebug() << "m_move_file_path = " << m_move_file_path;
        m_select_dirPB->setEnabled(true);
    });

    connect(m_select_dirPB, &QPushButton::clicked, this, [&]() {
        QListWidgetItem* item = m_book_list_widget->currentItem();
        if (!item) {
            QMessageBox::warning(this, "没有选择文件", "请选择要移动到哪个目录下");
            return;
        }
        QString dest_tmp = item->text();
        QString cur_dir = TcpClient::getInstance().get_current_dir();
        m_move_file_dest_path = cur_dir + "/" + dest_tmp;
        qDebug() << "m_move_file_dest_path = " << m_move_file_dest_path;
        m_select_dirPB->setEnabled(false);

        //发送PDU
        int src_len = m_move_file_path.size();
        int dest_len = m_move_file_dest_path.size();
        PDU* pdu = makePDU(src_len + dest_len + 2);
        pdu->uiMsgType = ENUM_MSG_TYPE_MOVE_FILE_REQUEST;
        sprintf(pdu->caData, "%d %d %s", src_len, dest_len, m_move_file_name.toStdString().c_str());
        strncpy((char*)pdu->caMsg, m_move_file_path.toStdString().c_str(), m_move_file_path.size());
        strncpy((char*)pdu->caMsg+src_len+1, m_move_file_dest_path.toStdString().c_str(), m_move_file_dest_path.size());

        TcpClient::getInstance().getTcpSocket().write((char*)pdu, pdu->uiPDULen);
        pdu->printPDU();
        free(pdu); pdu = NULL;
    });

}

void Book::show_file(const PDU *pdu)
{
    if (pdu == NULL) return;
    //先清除原来的内容;
    int size_ = m_book_list_widget->count();
    QListWidgetItem* tmp;
    for (int i = size_-1; i >= 0; i--) {
        tmp = m_book_list_widget->item(i);
        m_book_list_widget->removeItemWidget(tmp);
        delete tmp; tmp = NULL;
    }

    FileInfo* p_file_info = NULL;
    int cnt = pdu->uiMsgLen/sizeof(FileInfo);
    for (int i = 0; i < cnt; i++) {
        p_file_info = (FileInfo*)(pdu->caMsg)+i;
        // QString file_path = QString("%1\t %2").arg(p_file_info->file_name).arg(p_file_info->file_type);
        QListWidgetItem* pItem = new QListWidgetItem;
        if (p_file_info->file_type == 0) {
            pItem->setIcon(QIcon(QPixmap(":/img/dir.jpg")));
        } else if (p_file_info->file_type == 1) {
            pItem->setIcon(QIcon(QPixmap(":/img/momal.jpg")));
        }
        pItem->setText(p_file_info->file_name);
        m_book_list_widget->addItem(pItem);
    }
}

void Book::flush_file()
{
    QString cur_path = TcpClient::getInstance().get_current_dir();
    PDU* pdu = makePDU(cur_path.size()+1);
    pdu->uiMsgType = ENUM_MSG_TYPE_FLUSH_FILE_REQUEST;
    strncpy((char*)pdu->caMsg, cur_path.toStdString().c_str(), cur_path.size());

    TcpClient::getInstance().getTcpSocket().write((char*)pdu, pdu->uiPDULen);
    // pdu->printPDU();
    free(pdu); pdu = NULL;
}

/*
文件在服务器上, 客户端上路径肯定不存在,
*/
// void Book::enter_folder(const QString& dir_name)
// {
//     QString cur_path = TcpClient::getInstance().get_current_dir();
//     if (dir_name == ".") {  //.表示当前目录, 这不用处理
//         return;
//     } else if (dir_name != "..") { //..表示上一级目录, 等于它就不用拼接了
//         cur_path += "/"; cur_path += dir_name;
//     }
//     // TcpClient::getInstance().set_current_dir(cur_path);

//     str_enter_folder = cur_path;
//     qDebug() << cur_path;
//     PDU* pdu = makePDU(cur_path.size()+1);
//     pdu->uiMsgType = ENUM_MSG_TYPE_FLUSH_FILE_REQUEST;
//     strncpy((char*)pdu->caMsg, cur_path.toStdString().c_str(), cur_path.size());

//     TcpClient::getInstance().getTcpSocket().write((char*)pdu, pdu->uiPDULen);
//     // pdu->printPDU();
//     free(pdu); pdu = NULL;
// }

void Book::clear_enter_dir()
{
    this->m_enter_dir.clear();
}

QString Book::get_enter_dir()
{
    return m_enter_dir;
}

void Book::dir_go_back() {
    QString cur_path = TcpClient::getInstance().get_current_dir();
    PDU* pdu;

    //删除目录后面的一项
    int len = cur_path.size();
    for (int i = len-1; i > 0; i--) {
        if (cur_path[i] == '/') {
            cur_path.chop(1);
            break;
        }
        cur_path.chop(1);
    }
    qDebug() << "pop path: " << cur_path;

    m_go_back_dir = cur_path;
    pdu = makePDU(cur_path.size()+1);
    pdu->uiMsgType = ENUM_MSG_TYPE_GO_BACK_DIR_REQUEST;
    strncpy((char*)pdu->caMsg, cur_path.toStdString().c_str(), cur_path.size());

    TcpClient::getInstance().getTcpSocket().write((char*)pdu, pdu->uiPDULen);
    // pdu->printPDU();
    free(pdu); pdu = NULL;
}

QString Book::get_go_back_dir() const
{
    return m_go_back_dir;
}

void Book::setGo_back_dir(const QString &newGo_back_dir)
{
    // m_go_back_dir = newGo_back_dir;
    m_go_back_dir.clear();
}

QString Book::save_path() const
{
    return m_save_path;
}

bool Book::download_flag() const
{
    return m_download_flag;
}

void Book::setDownload_flag(bool newDownload_flag)
{
    m_download_flag = newDownload_flag;
}

QString Book::shar_file_name() const
{
    return m_shar_file_name;
}

